﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using TechNewLogic.GraphIT.Hv;
using TechNewLogic.GraphIT.Hv.Vertical;

namespace TestHost
{
	/// <summary>
	/// Interaction logic for DemoControl.xaml
	/// </summary>
	public partial class DemoControl : IDisposable
	{
		private readonly IResetDemo _resetDemo;
		private static readonly Random Random;

		static DemoControl()
		{
			Random = new Random((int)DateTime.Now.Ticks);
		}

		public DemoControl(IResetDemo resetDemo)
		{
			_resetDemo = resetDemo;
			InitializeComponent();

			//GuardReleaseVersion();

			_onlineOfflineLegend = new OnlineOfflineLegend(
				CurveDisplay,
				"AKZ",
				"Location",
				"Aggregate",
				"Medium",
				"Physical");
			legendHolder.Content = _onlineOfflineLegend;
		}

		private DateTime _startTime;
		private readonly Dictionary<TimeDoubleCurve, DataFactory> _curves
			= new Dictionary<TimeDoubleCurve, DataFactory>();

		private OnlineOfflineLegend _onlineOfflineLegend;

		private TimeDoubleCurve AddCurve(
			string uom,
			double min,
			double max,
			Color color,
			string descriptionText1,
			string descriptionText2,
			string descriptionText3,
			string descriptionText4,
			string descriptionText5,
			CurveDrawingMode curveDrawingMode,
			ValueFormat valueFormat = ValueFormat.FloatingComma,
			ValueFetchMode valueFetchMode = ValueFetchMode.LinearInterpolation)
		{
			const int maxCurves = 20;
			if (_curves.Count >= maxCurves)
			{
				MessageBox.Show("You cannot add more than " + maxCurves + " curves.");
				return null;
			}

			var curve = CurveDisplay.TimeDoublePlottingSystem.AddCurve(
				uom,
				min,
				max,
				color,
				curveDrawingMode,
				valueFormat: valueFormat, 
				valueFetchMode: valueFetchMode);

			curve.Description.DescriptionText1 = descriptionText1;
			curve.Description.DescriptionText2 = descriptionText2;
			curve.Description.DescriptionText3 = descriptionText3;
			curve.Description.DescriptionText4 = descriptionText4;
			curve.Description.DescriptionText5 = descriptionText5;

			_curves.Add(curve, null);

			return curve;
		}

		private void GenerateData(TimeDoubleCurve curve, bool randomData)
		{
			var min = curve.DoubleAxis.ActualLowerBound;
			var max = curve.DoubleAxis.ActualUpperBound;
			var dataFactory = DataFactory.Attach(
				curve,
				_startTime,
				min,
				max,
				1,
				(max - min) / 500,
				(max - min) / 100,
				(max - min) / 2);

			// all in all: 50min
			var first = Random.Next(5, 30);
			var second = Random.Next(5, 50 - first - 5);
			second = second > 15 ? 15 : second;
			var third = 50 - first - second;
			if (!randomData)
				dataFactory.AppendSine(TimeSpan.FromMinutes(50), (_curves.Count + 1) / 15d);
			else
			{
				dataFactory.AppendPoints(TimeSpan.FromMinutes(first));
				dataFactory.AppendGap(TimeSpan.FromMinutes(second));
				dataFactory.AppendPoints(TimeSpan.FromMinutes(third));
			}

			curve.MinMinBelt = -0.9 + dataFactory.Offset;
			curve.MinBelt = -0.4 + dataFactory.Offset;
			curve.MaxBelt = 0.3 + dataFactory.Offset;
			curve.MaxMaxBelt = 0.7 + dataFactory.Offset;

			//// Belt
			//if (_curves.Count == 1)
			//{
			//    curve.MinMinBelt = -0.9 + dataFactory.Offset;
			//    curve.MinBelt = -0.4 + dataFactory.Offset;
			//    curve.MaxBelt = 0.3 + dataFactory.Offset;
			//    curve.MaxMaxBelt = 0.7 + dataFactory.Offset;
			//}

			//_curves.Add(curve, dataFactory);
		}

		private void GenerateBinaryData(TimeDoubleCurve curve)
		{
			var min = curve.DoubleAxis.ActualLowerBound;
			var max = curve.DoubleAxis.ActualUpperBound;
			var dataFactory = DataFactory.Attach(
				curve,
				_startTime,
				min,
				max,
				0.01,
				(max - min) / 500,
				(max - min) / 100,
				(max - min) / 2);

			// all in all: 50min
			dataFactory.AppendBinary(TimeSpan.FromMinutes(50));

			//curve.MinMinBelt = -0.9 + dataFactory.Offset;
			//curve.MinBelt = -0.4 + dataFactory.Offset;
			//curve.MaxBelt = 0.3 + dataFactory.Offset;
			//curve.MaxMaxBelt = 0.7 + dataFactory.Offset;

			//_curves.Add(curve, dataFactory);
		}

		public string ApplicationTitle
		{
			get { return "CLR Runtime:   " + Environment.Version; }
		}

		private void Print_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.Print(10);
		}

		private void PrintPreview_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.ShowPrintPreview();
		}

		private void ToggleOnline_Click(object sender, RoutedEventArgs e)
		{
			if (CurveDisplay.TimeDoublePlottingSystem.IsOnline)
				CurveDisplay.TimeDoublePlottingSystem.DisableOnlineMode();
			else
				CurveDisplay.TimeDoublePlottingSystem.EnableOnlineMode(DateTime.Now.Ticks);
		}

		private void Reset_Click(object sender, RoutedEventArgs e)
		{
			Reset();
		}

		private void Reset()
		{
			//_resetDemo.Reset();

			var tmpCurves = new TimeDoubleCurve[_curves.Keys.Count];
			_curves.Keys.CopyTo(tmpCurves, 0);

			// ungroup all axes before removing curves
			var groups = new List<DoubleAxesGroup>();
			groups.AddRange(CurveDisplay.TimeDoublePlottingSystem.AxesGroups);
			foreach (var doubleAxesGroup in groups)
			{
				CurveDisplay.TimeDoublePlottingSystem.UngroupAxesGroup(doubleAxesGroup);
			}

			// remove curves from plotting system
			foreach (var curveToRemove in tmpCurves)
			{
				CurveDisplay.TimeDoublePlottingSystem.RemoveCurve(curveToRemove);
			}

			_curves.Clear();

			_startTime = new DateTime(2012, 3, 25, 0, 0, 0);
			//_startTime = DateTime.UtcNow;
			CurveDisplay.TimeDoublePlottingSystem.TimeAxis.SetBounds(
				//new DateTime(2012, 3, 25, 0, 0, 0),
				//new DateTime(2012, 3, 25, 5, 0, 0));
				_startTime.Ticks,
				_startTime.AddHours(5).Ticks);

			//_refreshCurveDataTimer = new DispatcherTimer();
			//_refreshCurveDataTimer.Interval = TimeSpan.FromSeconds(3);
			//_refreshCurveDataTimer.Tick += refreshCurveDataTimer_Tick;
			//_refreshCurveDataTimer.Start();

			var curve = AddCurve("%", 0, 100, Colors.Green, "R2033", "House 20", "BHKW",
				"Istwert", "Power Calc.", CurveDrawingMode.SimpleLine());
			GenerateData(curve, false);
			curve = AddCurve("m³/h", 0, 10, Colors.Yellow, "U2031", "House 20", "BHKW", "Gas",
				"Quantity", CurveDrawingMode.SimpleLine());
			GenerateData(curve, false);
			curve = AddCurve("kW", 0, 100, Colors.Red, "U2002", "House 20", "BHKW", "Heater",
				"Heating Actual", CurveDrawingMode.SimpleLine());
			GenerateData(curve, false);
			curve = AddCurve("°C", -20, 20, Colors.Blue, "T2051", "House 20", "Outer Temp.",
				"Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleAuto());
			GenerateData(curve, false);
			curve = AddCurve("°C", 20, 60, Colors.Orange, "T2051", "House 20", "Outer Temp.",
				"Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleHighest());
			GenerateData(curve, false);
			curve = AddCurve("°C", -0.2, 1.2, Colors.PaleTurquoise, "T2051", "House 20",
				"Outer Temp.", "Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleHighest(),
				ValueFormat.Binary, ValueFetchMode.LeftNeighbor);
			GenerateBinaryData(curve);
			CurveDisplay.TimeDoublePlottingSystem.AxesGroups.First(
				it => it.DoubleAxes.Contains(curve.DoubleAxis)).IgnoreCanvasMovementOrZoom = true;
		}

		#region Implementation of IDisposable

		public void Dispose()
		{
			_onlineOfflineLegend.Dispose();
			CurveDisplay.Dispose();
		}

		#endregion

		#region Custom Controls

		private void AddCustomControl_Click(object sender, RoutedEventArgs e)
		{
		}

		private void AddCustomControl1_Click(object sender, RoutedEventArgs e)
		{
		}

		private void RemoveCustomControl_Click(object sender, RoutedEventArgs e)
		{
		}

		private void AddCustomControl2_Click(object sender, RoutedEventArgs e)
		{
		}

		private void RemoveCustomControl2_Click(object sender, RoutedEventArgs e)
		{
		}

		#endregion

		private void RemoveCurve_Click(object sender, RoutedEventArgs e)
		{
			if (_curves.Count == 0)
				return;
			var curve = _curves.First();
			CurveDisplay.TimeDoublePlottingSystem.RemoveCurve(curve.Key);
			_curves.Remove(curve.Key);
		}

		private void AppendData_Click(object sender, RoutedEventArgs e)
		{
			if (_curves.Count == 0)
				return;
			var curve = _curves.First();
			curve.Value.AppendPoints(TimeSpan.FromSeconds(10));
		}

		private void PrependData_Click(object sender, RoutedEventArgs e)
		{
			throw new NotImplementedException();
			//if (_curves.Count == 0)
			//    return;
			//var curve = _curves.First();
			//curve.Value.PrependPoints(TimeSpan.FromSeconds(10));
		}

		private void ToggleVisibility_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.Curves.OfType<TimeDoubleCurve>().ToList().ForEach(it => it.IsVisible = !it.IsVisible);
		}

		private void ShowAxes_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.TimeDoublePlottingSystem.SetScalesVisibility(true, true, true);
		}

		private void HideAxes_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.TimeDoublePlottingSystem.SetScalesVisibility(false, false, false);
		}

		private void Dispose_Click(object sender, RoutedEventArgs e)
		{
			_resetDemo.Reset();
		}

		private void ChangeColor_Click(object sender, RoutedEventArgs e)
		{
			var curve = _curves.Keys.FirstOrDefault();
			if (curve == null)
				return;
			curve.Stroke = curve.Stroke == Colors.Yellow ? Colors.Blue : Colors.Yellow;
		}
	}
}
